﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NTL.Assignment
{
    /// <summary>
    /// UI code for duplicate file content finder.
    /// </summary>
    public partial class DuplicateFinderUI : Form
    {
        /// <summary>
        /// Search directory
        /// </summary>
        private string searchDirectory;
      
        // Blocking queue
        private ConcurrentQueue<IList<string>> blockingQueue = new ConcurrentQueue<IList<string>>();

        // The reader that discovers duplicate files.
        private FileReader reader;

        // The output writer of the discovered duplicate files. 
        private FileWriter writer;

        private string restartReadersText = "Restart Readers";

        private string startReadersText = "Start Readers";

        private string restartWriterText = "Restart Writer";

        private string startWriterText = "Start Writer";

        private string pauseWriterText = "Pause Writer";

        private string resumeWriterText = "Resume Writer";

        private string pauseReadersText = "Pause Readers";

        private string resumeReadersText = "Resume Readers";

        private int threads = 1;

        public DuplicateFinderUI()
        {
            InitializeComponent();

            this.FormClosed += DuplicateFinderUI_FormClosed;
        }

        private void DuplicateFinderUI_Load(object sender, EventArgs e)
        {
            threadCountTextBox.Text = threads.ToString();

            pauseReadersButton.Enabled = false;
            pauseWriterButton.Enabled = false;
            abortReadersButton.Enabled = false;
            abortWriterButton.Enabled = false;
        }

        private void DuplicateFinderUI_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (reader != null)
            {
                reader.Abort();
            }

            if (writer != null)
            {
                writer.Abort();
            }

            Application.Exit();     
        }

        private void searchDirectoryBrowserDialog_HelpRequest(object sender, EventArgs e)
        {
        }

        private void startReadersButton_Click(object sender, EventArgs e)
        {
            try
            {
                threads = Int32.Parse(threadCountTextBox.Text);

                if (threads <= 0)
                {
                    MessageBox.Show(
                        "Number of threads must be a positive integer !",
                        "Invalid number of threads",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);

                    return;
                }
                else
                {
                    if (string.IsNullOrEmpty(searchDirectory))
                    {
                        MessageBox.Show(
                            "The directory to search for files has to be set !",
                            "Search directory not set",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);

                        return;
                    }
                    else if ((!string.IsNullOrEmpty(outputFileDirectoryBrowserDialog.SelectedPath)) && 
                        outputFileDirectoryBrowserDialog.SelectedPath.Contains(searchDirectory))
                    {
                        DisplayOutputFileInsideSearchDirectoryMessage();
                        return;
                    }
                    else
                    {
                        startReadersButton.Enabled = false;
                        pauseReadersButton.Enabled = true;
                        abortReadersButton.Enabled = true;

                        if (startReadersButton.Text.Equals(startReadersText))
                        {
                            startReadersButton.Text = restartReadersText;
                            reader = new FileReader(blockingQueue, searchDirectory, threads);
                            reader.Read();
                        }
                        else
                        {
                            // Set if we want to start with different paths.
                            reader.ReaderThreadCount = threads;
                            reader.SearchDirectoryPath = searchDirectory;

                            // Restart readers
                            reader.Restart();
                        }

                        DisplaySummary();
                    }
                }
            }
            catch (FormatException)
            {
                MessageBox.Show(
                    "Unable to parse the number of threads field. It must be a positive integer !",
                    "Invalid number of threads",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    ex.Message,
                    "Error starting readers",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }

        private void startWriterButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(outputFileTextBox.Text))
                {
                    MessageBox.Show(
                        "Full path for the output file name cannot be empty !",
                        "Missing parameer",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);
                }
                else
                {
                    if (!string.IsNullOrEmpty(searchDirectoryBrowserDialog.SelectedPath))
                    {
                        if (outputFileTextBox.Text.Contains(searchDirectoryBrowserDialog.SelectedPath))
                        {
                            DisplayOutputFileInsideSearchDirectoryMessage();
                            return;
                        }
                    }

                    pauseWriterButton.Enabled = true;
                    abortWriterButton.Enabled = true;
                    startWriterButton.Enabled = false;

                    if (startWriterButton.Text.Equals(startWriterText))
                    {
                        startWriterButton.Text = restartWriterText;
                        writer = new FileWriter(blockingQueue, outputFileTextBox.Text);
                        writer.Write();
                    }
                    else
                    {
                        // Set output file path, if we want to change that on restart.
                        writer.OutputFileFullPath = outputFileTextBox.Text;

                        // Restart writer
                        writer.Restart();
                    }

                    DisplaySummary();
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(
                    exception.Message,
                    "Error occured in the writer",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void pauseReadersButton_Click(object sender, EventArgs e)
        {
            if (pauseReadersButton.Text.Equals(pauseReadersText))
            {
                reader.Pause();
                pauseReadersButton.Text = resumeReadersText;
            }
            else if (pauseReadersButton.Text.Equals(resumeReadersText))
            {
                reader.Resume();
                pauseReadersButton.Text = pauseReadersText;
            }

            DisplaySummary();
        }

        private void browseForDirectoryButton_Click(object sender, EventArgs e)
        {
            if (searchDirectoryBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                searchDirectory = searchDirectoryBrowserDialog.SelectedPath;
                searchDirectoryTextBox.Text = searchDirectory;
            }
        }

        // Abort button click
        private void abortReadersButton_Click(object sender, EventArgs e)
        {
            reader.Abort();

            pauseReadersButton.Enabled = false;
            abortReadersButton.Enabled = false;
            startReadersButton.Enabled = true;
            pauseReadersButton.Text = pauseReadersText;

            DisplaySummary();
        }

        private void pauseWriterButton_Click(object sender, EventArgs e)
        {
            if (pauseWriterButton.Text.Equals(pauseWriterText))
            {
                writer.Pause();
                pauseWriterButton.Text = resumeWriterText;
            }
            else if (pauseWriterButton.Text.Equals(resumeWriterText))
            {
                pauseWriterButton.Text = pauseWriterText;
                writer.Resume();
            }

            DisplaySummary();
        }

        private void abortWriterButton_Click(object sender, EventArgs e)
        {
            writer.Abort();

            pauseWriterButton.Enabled = false;
            abortWriterButton.Enabled = false;
            startWriterButton.Enabled = true;
            pauseWriterButton.Text = pauseWriterText;

            DisplaySummary();
        }

        private void selectOutputFilePathButton_Click(object sender, EventArgs e)
        {
            if (outputFileDirectoryBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                outputFileTextBox.Text = Path.Combine(outputFileDirectoryBrowserDialog.SelectedPath, "output.txt");
            }
        }

        private void DisplaySummary()
        {
            if (reader != null)
            {
                processedFilesValue.Text = reader.Count.ToString();
            }

            if (writer != null)
            {
                processedPairsValue.Text = writer.Count.ToString();
            }
        }

        private void DisplayOutputFileInsideSearchDirectoryMessage()
        {
            MessageBox.Show(
                "Output file path cannot be inside the search directory !",
                "Invalid path",
                MessageBoxButtons.OK,
                MessageBoxIcon.Exclamation);
        }

        private void outputFileDirectoryBrowserDialog_HelpRequest(object sender, EventArgs e)
        {
        }

        private void summaryButton_Click(object sender, EventArgs e)
        {
            DisplaySummary();
        }
    }
}
